﻿#include "rec_write_base.h"
#include "rec_data_io.h"
#include "storage_api.h"

extern   StorageConfig	g_storageCfg;

CRecWriteBase::CRecWriteBase()
{
	m_fileHeadOffset= 0;
	m_channel =0;
	m_pfifo_buf = new CFIFO_buf();
	m_curPos = SIZE_8KB;
	m_headBuf = new uchar_t[m_curPos];
	memset(m_headBuf,0,m_curPos);
	m_headBufSize = SIZE_8KB;
	m_pFile = NULL;
	memset(&m_curSeg,0,REC_SEG_LEN);
	memset(&m_fileHead,0,REC_HEADINFO_LEN);
	m_bstop = false;
	m_bsuspense = false;
	m_bRawDev = false;
	m_bUseFIFO = true;
	m_storageName = NULL;
	m_switchMod = 0;			 //文件切换模式
}

CRecWriteBase::~CRecWriteBase()
{
	if(NULL != m_headBuf)
	{
		delete [] m_headBuf;
	}

	if( NULL != m_pfifo_buf)
	{
		delete m_pfifo_buf;
	}
}

int CRecWriteBase::Init(bool bUserFIFO,int fifoSize)
{
	if(bUserFIFO)
	{
		m_pfifo_buf->open(fifoSize);
	}
	else
	{
		m_pfifo_buf->close();
	}

	return 0;
}

int CRecWriteBase::DetectFileHead(uchar_t * dataBuf, int dataSize)
{
	static char magic[8] = STFS_RECORD_MAGIC;
	int diffOff = 0;
	STFS_REC_FILEHEAD* pHead = (STFS_REC_FILEHEAD*)dataBuf;
	bool bFound = false;
	while(diffOff < STFS_REC_IDX_OFFSET)
	{
		if(memcmp(pHead->magic,magic,MAGIC_LEN) == 0)
		{	//±È½ÏÇ©Ãû
			bFound = true;
			break;
		}
		diffOff += SIZE_HDD_BLOCK1;
		pHead = (STFS_REC_FILEHEAD*)(dataBuf + diffOff);
		continue;
	}

	if(!bFound)
	{
		TRACE_ERR("Current file not record file.\n");
		return ERR_NOT_RECFILE;
	}
	m_fileHeadOffset = diffOff;
	memcpy(&m_fileHead,dataBuf + diffOff,REC_HEADINFO_LEN);
	return diffOff;

}

int  CRecWriteBase::ClearIndexArea()
{
	//清理一下索引区的头部和尾部
	int ret = m_pFile->WritePos(m_fileHead.idxOffset,m_frmIdx.GetBufAddr(),m_frmIdx.GetBufSize());
	if(ret < 0)
	{
		return ret;
	}
	return 0;
}

bool CRecWriteBase::IsSwitchFile(int curOffset)
{
	bool bRet = false;



	return bRet;
}

int CRecWriteBase::WriteDataAlign(const void * dataBuf , int dataSize)
{
	uchar_t buf[SIZE_4KB] = {0};
	memcpy(buf,dataBuf,dataSize);
	return m_pFile->WritePos(m_fileHead.dataOffset,buf,dataSize);
}

int  CRecWriteBase::InitFifoBuf(int bufSize)
{
	int	ret = m_frmIdx.Open(bufSize,STFS_REC_IDX_OFFSET,512);
	int buf_size = 0;
	if( 0 != g_storageCfg.chInfo[m_channel].rec_cache_sz)
	{
		buf_size = g_storageCfg.chInfo[m_channel].rec_cache_sz;
	}
	else
	{
		buf_size = SIZE_MB(2);
	}

	ret = m_pfifo_buf->open(buf_size);

	return ret;
}

int CRecWriteBase::OpenFile(const char * storagePath, uint32_t fileIndex, uint32_t fileSize)
{
	int ret = 0;
	char filePath[60] = {0};
	uint64_t fileLBA = 0;
#if 0
	uint64_t fileLBA = g_diskInfoSet.GetAssignFileLBA(storagePath,fileIndex);
	bRaw = CSerialFileBase::IsRawDevice(storagePath);
	m_bRawDev    = bRaw;
	if(NULL == m_pFile)
	{
		m_pFile = g_serialFileFac.CreateSerialFile(storagePath);

	}
	else
	{
		if(m_bRawDev != bRaw)
		{
			delete m_pFile;
			m_pFile = g_serialFileFac.CreateSerialFile(storagePath);
		}
	}

	if(bRaw)
	{
		CSCSI_Dev* pDev = g_scsiDevFac.CreateScsiDev(storagePath);
		if( NULL == pDev)
		{
			TRACE_ERR("No device %s .\n", storagePath);
			return ERR_NO_DEVICE;
		}

		ret = m_pFile->Open(pDev,fileLBA,fileSize,SCSI_RDWR);
	}
	else
	{
		GetFileDestPath(tmpPath,storagePath);
#ifdef _WIN32
		strcat(tmpPath,"Record\\");
#else
		strcat(tmpPath,"Record//");
#endif
		if( -1 == access(tmpPath,0))
		{
			GetFileDestPath(tmpPath,storagePath);
#if 0
//不使用目录
#ifdef _WIN32
			SECURITY_ATTRIBUTES sa;
			sa.nLength				= sizeof(SECURITY_ATTRIBUTES);
			sa.lpSecurityDescriptor = NULL;
			sa.bInheritHandle       = 0;
			CreateDirectory(tmpPath,&sa);
#else
			char cmd[80] = {0};
			sprintf(cmd,"mkdir -p %s",tmpPath);
			system(cmd);
#endif
#endif
		}

		sprintf(filePath,"%s%05d.asf",tmpPath,fileIndex);
		TRACE("FilePath %s .\n",filePath);
#ifdef _WIN32
		if( -1 == access(filePath ,0))
		{
			ret = CSerialFileBase::AllocSpace(filePath,fileSize);
			if(ret < 0)
			{
				return ret;
			}
		}
#endif
		ret = m_pFile->Open(filePath,fileLBA,fileSize,SCSI_RDWR);
	}
#endif // 0

	return ret;
}
int CRecWriteBase::Close()
{
	int ret = 0;
	if(NULL == m_pFile)
	{
		return ERR_FILE_NOOPEN;
	}

	m_fileHead.fileLen = m_curPos;
	m_fileHead.idxNum  = m_recIdx.NO;
	m_fileHead.recNum  = m_curSeg.segNO + 1;
	m_fileHead.writeStatus = STFS_REC_END_FLAG;

	m_curSeg.dataLen = m_curPos    - m_curSeg.data_endpos;
	m_curSeg.idxNum  = m_recIdx.NO - m_curSeg.idx_startNo;
	m_curSeg.tmEnd   = m_fileHead.endTime;

	int wait_count = 200;	// 超时3秒失败（300 * 10 ms）
	int leaf_size = 0;
	if(!m_bUseFIFO)
	{
		uint32_t ioOffset = 0;
		uint32_t dataSize = m_frmIdx.GetDataSize();
		uchar_t * pBuf    = m_frmIdx.GetWriteBuffAddr(ioOffset,dataSize);
		if(NULL !=m_pFile)
		{   //写入索引
			ret = m_pFile->WritePos(ioOffset,pBuf,dataSize);
		}
	}
	else
	{
		if(0 != m_pfifo_buf->GetDataSize())
		{
			m_bstop =true; //设置停止录像 ，等待FIFO中数据写完成后退出
			while( true)//m_status != FILE_WRITE_FAIL)
			{	/*
				等待读写IO完成
				*/
				wait_count--;
				if(wait_count <= 0)
				{
					TRACE_ERR("Time out for close rec file. CH %d m_status %d \n ",m_channel, m_pFile->GetStatus());
					break;
				}

				if(FILE_DEVICE_LOST == m_pFile->GetStatus())
				{
					TRACE_ERR("No device %s  LBA %lld \n",m_pFile->get_device_name(),m_pFile->get_lba_start());
					break;
				}

				if(wait_count < 200)
				{
					if( -1 == access(m_pFile->get_device_name(),0))
					{
						TRACE_ERR("CH%02d Device %s is lost LBA %lld \n",m_channel,m_pFile->get_device_name(),m_pFile->get_lba_start());
						break;
					}
				}

				if((leaf_size = m_pfifo_buf->GetDataSize()) == 0)
				{
					//TRACE("CH %d LBA %lld dev %s End all data write.\n", m_channel,m_baseLBA,m_scsi_dev->get_device_name());
					break;
				}
				CrossSleep(10);
				m_bstop = true;
			}

			m_pfifo_buf->reset(0);
		}
	}

	ret = WriteRecHeadInfo();
	
	//当文件是使用的是按块大小分配时，则在采用强制将文件分配到指定大小
	if( SWITHC_BY_SZMB == m_switchMod)
	{
		if(m_curPos + SIZE_MB(1) >= m_fileHead.fileSpace)
		{
			m_pFile->FillTotalSpace();
		}
	}

	m_pFile->Close();
		
	m_vecSeg.clear();
	memset(&m_curSeg,0,REC_SEG_LEN);
	memset(&m_recIdx,0,REC_INDEX_LEN);
	memset(&m_gpsIdx,0,sizeof(STFS_GPS_IDX));
	memset(m_headBuf,0,STFS_REC_IDX_OFFSET);

	return ret ;
}

int CRecWriteBase::IsNormalClose()
{
	if(m_pFile == NULL)
	{
		return ERR_FILE_OPEN;
	}

	if(STFS_REC_END_FLAG != m_fileHead.writeStatus)
	{
		if(	m_fileHead.endTime == m_fileHead.startTime)
		{
			return ERR_FILE_NOOPEN;
		}
	}

	return 0;
}

int CRecWriteBase::SeekToTime(time_t seekTm)
{

	return 0;
}

int CRecWriteBase::ReadFileInfo()
{
	int ret = 0;


	return ret;
}

int CRecWriteBase::ReadIndexInfo(uchar_t * buf,int buf_size)
{

	if(NULL == buf)
	{
		return ERR_EMPTY_POINT;
	}

	if(buf_size < m_fileHead.dataOffset - m_fileHead.idxOffset)
	{
		return ERR_BUF_TOO_LITTLE;
	}

	int max_num = buf_size / sizeof(STFS_REC_IDX);
	return m_frmIdx.GetFrmIdxData((STFS_REC_IDX*)buf,max_num);
}

int CRecWriteBase::ReadGPSInfo(uchar_t * buf,int buf_size)
{
	if(NULL == buf)
	{
		return ERR_EMPTY_POINT;
	}

	if(buf_size < m_fileHead.dataOffset - m_fileHead.idxOffset)
	{
		return ERR_BUF_TOO_LITTLE;
	}

	int max_num = buf_size / sizeof(STFS_GPS_IDX);
	return m_frmIdx.GetGpsIdxData((STFS_GPS_IDX*)buf,max_num);
}

int  CRecWriteBase::WriteGPSInfo(uchar_t * buf,int size)
{
	if(m_pFile == NULL ||m_pFile->is_closed())
	{
		return ERR_FILE_NOOPEN;
	}
	STFS_GPS_IDX  *       pGpsIdx = (STFS_GPS_IDX*)buf;			//GPS信息索引记录
	if(pGpsIdx->magic != STFS_GPS_IDX_SIG)
	{
		CROSS_ASSERT(false);
	}
	if(m_gpsIdx.tmMS !=0 )
	{
		if((pGpsIdx->tmMS - m_gpsIdx.tmMS) < STFS_1SEC_MS)
		{
			m_gpsIdx.tmMS = pGpsIdx->tmMS;
			return ERR_PARAM;
		}
	}

	m_frmIdx.WriteGpsInfo(buf,REC_INDEX_LEN);
	m_gpsIdx.tmMS = pGpsIdx->tmMS;

	return 0;
}

void CRecWriteBase::InitHeadInfo(uint32_t fileSize,int fileIndex,int64_t startTime,PSTFS_RECINFO_EXTERN pExternInfo)
{
	char magic[8] = STFS_RECORD_MAGIC;
	memset(&m_fileHead,0,REC_HEADINFO_LEN);
	memset(&m_recIdx,0,REC_INDEX_LEN);
	memcpy(m_fileHead.magic,magic,MAGIC_LEN);
	m_recIdx.tmMS         = 0;
	m_recIdx.NO            = 0;
	m_fileHead.version     = STFS_RECORD_VERSION;
	m_fileHead.fileLen	   = fileSize;		//
	m_fileHead.fileSpace   = fileSize;		//
	m_fileHead.channel	   = m_channel;		//Í¨µÀ

	m_fileHead.recOffset   = STFS_REC_SEG_OFFSET + m_fileHeadOffset;

	m_fileHead.idxOffset   = STFS_REC_IDX_OFFSET;
	m_fileHead.dataOffset  = STFS_REC_DATA_OFFSET;

	m_fileHead.writeStatus = STFS_REC_WRITTING;
	m_fileHead.indexNO     = fileIndex;
	m_fileHead.frameRate   = pExternInfo->vRate;

	if(NULL != pExternInfo)
	{
		m_fileHead.recordSN    = pExternInfo->recordSN;
	}
	m_idxDiffComSize = (fileSize - m_fileHead.dataOffset)/STFS_MAX_RECIDX_NUM/3;

	if(startTime)
	{
		m_fileHead.startTime  = startTime;
	}
	else
	{
		m_fileHead.startTime   = m_endTime;
	}

	memset(&m_curSeg,0,REC_SEG_LEN);
	m_curSeg.segNO      = 0;
	m_curSeg.data_start = m_curSeg.data_endpos = STFS_REC_DATA_OFFSET;
	m_curSeg.tmStart	= startTime;
	m_endTime           = startTime;
	m_vecSeg.push_back(m_curSeg);
}

void  CRecWriteBase::SetSegmentInfo(STFS_REC_SEG & curSeg)
{
	int bufOff = m_fileHead.recOffset + m_vecSeg.size() * REC_SEG_LEN;
	memcpy(m_headBuf + bufOff,&curSeg,REC_SEG_LEN);
	m_vecSeg.push_back(curSeg);

}

void CRecWriteBase::PauseRec(REC_FILE_INFO & recordInfo)
{
	if( 0 == m_curSeg.segNO )
	{
		recordInfo.length = m_curSeg.dataLen = m_curPos;
	}
	else
	{
		recordInfo.length = m_curPos - m_curSeg.data_start;
	}

	m_fileHead.fileLen = m_curPos;
	m_fileHead.idxNum  = m_recIdx.NO;
	m_fileHead.recNum  = m_curSeg.segNO;
	int ret = 0;

	if(ret != REC_HEADINFO_LEN)
	{
		TRACE_CBS("Write record head fail.\n");
	}

#ifdef _DEBUG
	TRACE("CH%02d seg %d - %d IFrame Index %d\n",m_fileHead.channel,m_fileHead.indexNO,m_curSeg.segNO, m_recIdx.NO);
	PrintTimeMs(m_curSeg.tmStart,m_endTime,"Pause Record-seg ");
#endif

	m_curSeg.data_endpos = m_curPos;
	m_curSeg.idxNum  = m_recIdx.NO - m_curSeg.idx_startNo;
	m_curSeg.dataLen = m_curPos    - m_curSeg.data_start;

	m_curSeg.tmStart = 0;
	m_curSeg.tmEnd   = 0;
	m_curSeg.magic   = STFS_REC_SEG_SIG;


	int last_seg = 0;
	if(0 != m_vecSeg.size())
	{
		last_seg = m_vecSeg.size() - 1;
	}

	memcpy(&m_vecSeg[last_seg],&m_curSeg,REC_SEG_LEN);

	TRACE_ERR("CH%02d Set Segment info  idx %d .\n",m_fileHead.channel,m_curSeg.segNO);
	PrintTimeMs(m_curSeg.tmStart,m_curSeg.tmEnd,"Set Segment");
	WriteRecHeadInfo();

	m_curSeg.tmStart = m_endTime;
	m_bsuspense      = true;
}

void CRecWriteBase::Resume(REC_FILE_INFO & recordInfo)
{
	m_curSeg.segNO       = recordInfo.segIndex;
	m_curSeg.data_start  = m_curSeg.data_endpos = m_curPos;
	m_curSeg.idx_startNo = m_recIdx.NO;
  	m_curSeg.type        = recordInfo.recordType;
	m_curSeg.tmEnd       = m_curSeg.tmStart     = recordInfo.tmStart;
	m_endTime            = recordInfo.tmStart;	//修改最后一帧的时间。
	m_vecSeg.push_back(m_curSeg);
	WriteRecHeadInfo();
}

int   CRecWriteBase::Flush_HeadInfo(bool bEndRecord)
{
	if(!bEndRecord)
	{
		if(!m_frmIdx.IsNeedFlush())
		{
			return false;
		}
	}
	uint32_t ioOffset = 0;
	uint32_t dataSize = m_frmIdx.GetDataSize();

	if(0 == dataSize)
	{
		return 0;
	}

	if(!bEndRecord)
	{   //关闭文件必须写入
		if(dataSize < SIZE_HDD_BLOCK1/2)
		{
			return 0;
		}
	}

	uchar_t * pBuf    = m_frmIdx.GetWriteBuffAddr(ioOffset,dataSize);
	int ret = m_pFile->WritePos(ioOffset + STFS_REC_IDX_OFFSET,pBuf,dataSize);
	m_frmIdx.UpdataLastWritePos();

	return ret;
}

void  CRecWriteBase::Start_FlushData(uint32_t dataOffset)
{

	m_pFile->Seek(dataOffset,SEEK_SET);

	g_rec_dataIO.AddRecordTask(m_storageName,m_channel,this);
}

int CRecWriteBase::WriteFIFO( unsigned char * data_buf, uint32_t data_size)
{
	int ret;
	int wait_count = 400;  //最大超时8S
	uint32_t free_space = 0;

	CROSS_ASSERT(m_pfifo_buf != NULL);
;   CROSS_ASSERT(m_pFile != NULL);

	int status = m_pFile->GetStatus();
	if(FILE_WRITE_FAIL  == status ||
	   FILE_DEVICE_LOST == status)
	{
		ret = ERR_WRITE_FAIL;
		TRACE_ERR("Write FIFO fail status %d m_lastRet %d \n", status,m_pFile->GetLastErr());
		return ret;
	}

	for(int idx = 0 ; idx < 3; idx++)
	{
		ret = m_pfifo_buf->write(data_buf,data_size);

		if(ret == (int)data_size)
		{
            ret = m_pfifo_buf->GetCurWarter();
			break;
		}

		if(FIFO_ERR_NOTENOUGH == ret)
		{
			while(wait_count>= 0)
			{
				if( 0 == wait_count)
				{	//³
					TRACE_ERR("CH %02d Wait time too long.Free space %u data size %u\n",m_fileHead.channel,free_space,data_size);
					return FIFO_ERR_TIMEOUT;
				}


				if((FILE_WRITE_FAIL  == status) ||
				   (FILE_DEVICE_LOST == status))
				{
					TRACE_ERR("Write FIFO fail ,m_status %d error %d %s .\n",status,ret,strerror(ret));
					return -1;
				}

				CrossSleep(20);
				free_space = m_pfifo_buf->GetFreeSize();
				if(free_space >= data_size)
				{
					TRACE_ERR("CH %02d FIFO_ERR_NOTENOUGH free_space %d data_size %d wait_count %d \n",m_fileHead.channel,free_space,data_size,wait_count);
					break;
				}
				wait_count--;
			}
		}

		if((0 == idx) && (0 == wait_count))
		{
			TRACE_ERR("CH%02d Write Error time out.\n",m_fileHead.channel);
			return FIFO_ERR_TIMEOUT;
		}
	}

	return data_size;
}


int	 CRecWriteBase::AnsureKeyFrameSpace(uint32_t reserveSize)
{
	uint32_t dataSize     = 0;
	const int LAST_CHK_IDX = 5;

	dataSize = m_frmIdx.GetDataSize2KeyFrm(LAST_CHK_IDX,m_curPos);
	uint32_t freeSize = m_fileHead.fileSpace - m_curPos -reserveSize;
	if(freeSize < dataSize)
	{
		TRACE("Leaf Data Size %d free Size %d. \n",dataSize,freeSize);
		return ERR_DATA_AREA;
	}

	return 0;
}

void CRecWriteBase::GetDataSize2IFrm(uint32_t & dataSize,int lastIdxCnt)
{
	dataSize = m_frmIdx.GetDataSize2KeyFrm(lastIdxCnt,m_curPos);
#if 0
	RecIdxInfo* pIdxInfo = m_pFile->GetRecIdxInfo();
	if( 1 >= pIdxInfo->idx_cnt)
	{
		return;
	}

	STFS_REC_IDX * pIdx  = (STFS_REC_IDX*)(pIdxInfo->buf + pIdxInfo->idx_offset);
	uint32_t lastOffset  = pIdx[pIdxInfo->idx_cnt-1].offset;

	int idx  = 0;
	uint32_t maxDataSize = 0;
	uint32_t tmpSize     = 0;
	for(int idx = (pIdxInfo->idx_cnt - 2); idx >= 0;idx--)
	{
		tmpSize = lastOffset - pIdx[idx].offset;
		if(tmpSize > maxDataSize)
		{
			maxDataSize = tmpSize;
		}
		if( 0 == lastIdxCnt -- )
		{
			break;
		}

		lastOffset = pIdx[idx].offset;
	}
	dataSize = maxDataSize;
#endif
}

int CRecWriteBase::CreateRecIndex(int frmType,int frmLen,int64_t frmTm,uint32_t curPos)
{
	if( m_recIdx.NO >= 2)
	{
		uint32_t frmDiff = m_curPos - m_recIdx.offset;
		if(frmDiff <  m_idxDiffComSize)
		{
			return ERR_FOR_SAVE_IDX_SPACE;
		}
	}

	if(curPos < m_recIdx.offset )
	{
		TRACE_ERR("ch %d index %d curPos %d last recIdx offset %d .\n",m_fileHead.channel,m_fileHead.indexNO,curPos,m_recIdx.offset);
		return ERR_DATA_OVER_FILE;
	}

	m_recIdx.frameType = frmType;
	if(frmLen & 0x01)
	{
	    m_recIdx.frameLen  = frmLen +1;
	}
	else
	{
		m_recIdx.frameLen  = frmLen ;
	}

	m_recIdx.tmMS      =  frmTm;
	m_recIdx.offset     = curPos;
	m_recIdx.magic      = STFS_REC_IDX_SIG;
	m_fileHead.deviceID = 0;
	m_recIdx.NO++;

	m_frmIdx.WriteFrameIndex(&m_recIdx,REC_INDEX_LEN);

// 	if(!m_bRawDev)
// 	{
// 		uint32_t ioOffset = 0;
// 		uint32_t dataSize = m_frmIdx.GetDataSize();
// 		if(dataSize >= 512)
// 		{
// 			uchar_t * pBuf    = m_frmIdx.GetWriteBuffAddr(ioOffset,dataSize);
// 			m_pFile->WritePos(ioOffset,pBuf,dataSize);
// 			m_pFile->Flush();
// 			m_frmIdx.UpdataLastWritePos();
// 		}
// 	}

	return 0;
}

int  CRecWriteBase::WriteRecHeadInfo()
{
	CROSS_ASSERT(NULL != m_headBuf);
	CROSS_ASSERT(m_fileHeadOffset < m_headBufSize);
	if( NULL == m_pFile)
	{
		return ERR_FIFO_NOOPEN;
	}
	memcpy(m_headBuf + m_fileHeadOffset,&m_fileHead,REC_HEADINFO_LEN);

	if(0 != m_vecSeg.size())
	{
		memcpy(m_headBuf + m_fileHead.recOffset,&m_vecSeg[0],m_vecSeg.size() * REC_SEG_LEN);
	}
	int ret =  m_pFile->WritePos(0,m_headBuf,m_headBufSize);
	m_pFile->Flush();
	return ret;
}

bool CRecWriteBase::IsTimeOut(int timeOutMS)
{
	int64_t cntTime;
	time_t curTime;
	int timeDiff = 0;

	time(&curTime);
	cntTime = (int64_t)curTime * 1000;

	timeDiff = (int)(cntTime - m_pFile->GetLastWtTime());

	if(timeDiff >= timeOutMS || timeDiff < 0)
	{
		//TRACE("CH %d timeount. timeDiff %d data 526size: %d cur-offset %d \n",m_channel,timeDiff, m_pfifo_buf->GetDataSize(),m_cur_offset);
		return true;
	}
	else
	{
		return false;
	}
}

int CRecWriteBase::GetSegmentEndTime(int idx,int64_t startTime,int64_t & endTime)
{

	uchar_t * pBuf ;
	int   bufSize  = STFS_REC_DATA_OFFSET;
	pBuf = new uchar_t[bufSize];
	STFS_REC_IDX *pIdxBuf  = (STFS_REC_IDX *)pBuf;
	int ret = m_pFile->ReadPos(m_fileHead.idxOffset,pBuf,bufSize);
	if(ret < 0)
	{
		TRACE_ERR("RepairFile read head data size %d fail.\n",m_headBufSize);
		return ret;
	}

	uint32_t maxNum    = (uint32_t)(STFS_REC_DATA_OFFSET - STFS_REC_IDX_OFFSET)/REC_INDEX_LEN;
	uint32_t startTmSec = (uint32_t)(startTime/STFS_1SEC_MS);

	for(uint32_t i = 0 ; i < maxNum; i++)
	{
		if( STFS_REC_IDX_SIG != pIdxBuf[i].magic &&
			STFS_GPS_IDX_SIG  != pIdxBuf[i].magic)
		{
			if( IFrame!= pIdxBuf[i].frameType)
			{
				TRACE_ERR("Error data index %d.\n",i);

				break;
			}
			else
			{
				continue;
			}
		}

		if(pIdxBuf[i].tmMS < startTmSec)
		{
			continue;
		}
		else
		{
			if( 0 != pIdxBuf[i].tmMS)
			{
				endTime = (int64_t)pIdxBuf[i].tmMS + 1;
				endTime *= STFS_1SEC_MS;
			}


			if( i != maxNum-1 &&  pIdxBuf[i+1].tmMS - pIdxBuf[i].tmMS > 3 *STFS_1SEC_MS)
			{
				break;
			}
		}
	}
	if(endTime != startTime)
	{
		return 0;
	}
	if(idx < (int)m_vecSeg.size())
	{
		if( m_vecSeg[idx].tmEnd > startTime)
		{
			endTime = m_vecSeg[idx].tmEnd;
			return 0;
		}
	}

	return 0;
}

int CRecWriteBase::Flush_FIFOData(int time_out, int cache_water)
{
	int ret = 0;
	int write_size;
	uchar_t* pbuf     = NULL;
	uchar_t* pTailBuf = NULL;
	uint32_t leaf_size = 0;
	uint32_t data_size = 0;

	if( m_pFile == NULL ||
		m_pFile->is_closed())
	{

		return 0;
	}
	bool bNeedFlush = m_bstop ||m_bsuspense;

	ret = Flush_HeadInfo(bNeedFlush);
	if(ret < 0)
	{
		TRACE("Updata key frame idx OK. ret %d Rec-CH %d\n", ret,m_channel);
	}

	if(!bNeedFlush)
	{
		if( !IsTimeOut(time_out))
		{
			ret = m_pfifo_buf->GetCurWarter();
			if(ret <= cache_water)
			{
				return 0;
			}
		}
	}

	write_size = data_size = m_pfifo_buf->GetDataSize();
	if( 0 == data_size )
	{
		return 0;
	}

	m_bsuspense = false;
	uint32_t cur_offset = m_pFile->get_cur_offset();

	if( 0 != data_size && 0!= cur_offset)
	{
		if((data_size + cur_offset) > m_fileHead.fileSpace )
		{
			TRACE("CH%02d Over data size %d m_cur_offset %d m_fileSize %d\n",
				m_channel,data_size,cur_offset,m_fileHead.fileSpace);
			data_size = m_fileHead.fileSpace - cur_offset;
			//CROSS_ASSERT(false);
			m_pfifo_buf->ConsumeBuf(data_size);
		//	goto ERR_REC;
		}

		pbuf = m_pfifo_buf->GetBufOffset(data_size,&leaf_size,&pTailBuf);

		if( NULL != pTailBuf &&
			leaf_size != 0)
		{
			ret = m_pFile->WriteCachePos(m_pFile->get_cur_offset(),pTailBuf,leaf_size);
			if(ret < 0)
			{
				TRACE("2 Write data fail.ret %d  leaf_size %d \n",ret, leaf_size);
				goto ERR_REC;
			}

			if(leaf_size > data_size)
			{
				TRACE("Error leaf size.\n");
			}
			write_size = data_size - leaf_size;
			m_pfifo_buf->ConsumeBuf(leaf_size);//改进，分成两次释放内存空间
		}

		if(write_size == 0)
		{
			TRACE("CH%02d 1 Write data fail.write_size %03d ret %d \n",m_channel,write_size,ret);
		}

		if(NULL != pbuf &&  0 != write_size)
		{
			ret = m_pFile->WriteCachePos(m_pFile->get_cur_offset(),pbuf,write_size);
			if(ret != write_size)
			{
				TRACE(" 1 Write data fail.write_size %03d ret %d \n",write_size,ret);
				goto ERR_REC;
			}
		}

		m_pfifo_buf->ConsumeBuf(write_size);//改进，分成两次释放内存空间，如果内存分成两段时另外一段在写完第二段时释放
	}

	return 0;

ERR_REC:

	if(errno == ENOENT|| errno == ENODEV )
	{
		m_pFile->set_resualt(FILE_DEVICE_LOST);
	}
	else
	{
		m_pFile->set_resualt(FILE_WRITE_FAIL);
	}
	m_pfifo_buf->reset();
	TRACE(" Rec-CH  Flush_FIFOData Errord ret %d error %d",m_channel,ret,errno);
	return ret;
}
